package com.tsystems.school;

import java.util.LinkedList;

/**
 * Created by IntelliJ IDEA.
 * User: victorn
 * Date: 8/18/11
 * Time: 6:08 PM
 * To change this template use File | Settings | File Templates.
 */
public class Executor implements IExecutor, Runnable {

    private int threadsNumber;
    private LinkedList<Runnable> tasks;
    private Thread threads[];
    private boolean interrupted;

    /**
     *
     * @param threadsNumber  Number of threads to do some work
     */
    public Executor(int threadsNumber) {
        this.threadsNumber = threadsNumber;
        tasks = new LinkedList<Runnable>();
        threads = new Thread[threadsNumber];
        interrupted = false;
    }

    /**
     * Adds new task to execution queue
     *
     * @param task - new task
     */
    public void execute(Runnable task) {

        if (!interrupted) {
            synchronized (tasks) {
                tasks.addLast(task);
            }
        }
    }

    /**
     * Interrupts execution
     */
    public void interrupt() {
        interrupted = true;

        tasks.clear();
    }

    /**
     * Waits while all tasks are executed
     */
    public void join() {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    /**
     *  Returns index of the first free thread in the array
     *
     * @return Thread index
     */
    private int getFreeThread() {
        for (int i = 0; i < threadsNumber; i++) {
            if (threads[i] == null || threads[i].getState() == Thread.State.TERMINATED)
                return i;
        }

        return -1;
    }


    /**
     *  Check if all working threads are free
     *
     * @return  true if all threads are free, false if any thread isn't free
     */
    private boolean allFree() {

        synchronized (threads) {
            for (int i = 0; i < threadsNumber; i++) {
                if (threads[i] != null && threads[i].getState() != Thread.State.TERMINATED)
                    return false;
            }
        }

        return true;
    }

    private void executeAll() {
        while (true) {
            if (tasks.size() > 0) {
                synchronized (tasks) {
                    int freeThreadInd = getFreeThread();

                    if (freeThreadInd != -1) {
                        synchronized (threads) {
                            threads[freeThreadInd] = new Thread(tasks.getFirst());

                            tasks.removeFirst();

                            threads[freeThreadInd].start();
                        }
                    }
                }
            } else {
                if (interrupted && allFree()) {
                    break;
                }

            }
        }
    }

    public void run() {
        executeAll();
    }
}
